"""
Word文档导出服务模块
处理试卷导出为Word文档的所有逻辑
"""

import json
import logging
# 修复导入路径 - 使用相对导入
import uuid
from pathlib import Path
from typing import Dict, Any

from docx import Document
from docx.oxml.ns import qn
from datetime import date

# 使用绝对导入，只在backend目录设置__init__.py
from backend.config.constants import Config

logger = logging.getLogger(__name__)


class WordExportService:
    """Word导出服务类"""

    def __init__(self):
        self.export_dir = Path(Config.EXPORT_DIR)
        self.export_dir.mkdir(exist_ok=True)

    def export_to_word(self, data: str, filename: str = None, include_answers: bool = True) -> str:
        """导出试卷到Word文档

        Args:
            data: 试卷数据JSON字符串
            filename: 文件名
            include_answers: 是否包含答案

        Returns:
            生成的文件路径
        """
        try:
            # 解析JSON数据
            exam_data = self._parse_exam_data(data)

            # 创建Word文档
            doc = self._create_document(exam_data, include_answers)

            # 生成文件路径
            filepath = self._generate_filepath(filename)

            # 保存文档
            doc.save(str(filepath))

            logger.info(f"Word文档导出成功: {filepath}")
            return str(filepath)

        except Exception as e:
            logger.error(f"导出Word文档失败: {e}")
            raise

    def _parse_exam_data(self, data: str) -> Dict[str, Any]:
        """解析试卷数据"""
        try:
            exam_data = json.loads(data)

            # 验证数据格式
            if "questions" not in exam_data or not isinstance(exam_data["questions"], list):
                raise ValueError("数据格式错误，缺少questions字段")

            return exam_data

        except json.JSONDecodeError as e:
            logger.error(f"JSON解析失败: {e}")
            raise ValueError("无效的JSON数据")

    def _create_document(self, exam_data: Dict[str, Any], include_answers: bool) -> Document:
        """创建Word文档"""
        doc = Document()

        # 添加标题
        self._add_title(doc, exam_data)

        # 设置默认字体
        self._set_default_font(doc)

        # 添加试卷信息表格
        self._add_exam_info_table(doc, exam_data)

        # 添加空行
        doc.add_paragraph()

        # 添加题目
        self._add_questions(doc, exam_data.get("questions", []), include_answers)

        return doc

    def _add_title(self, doc: Document, exam_data: Dict[str, Any]):
        """添加标题"""
        title_text = f"{exam_data.get('grade', '未知年级')}{exam_data.get('subject', '未知科目')}练习卷"
        title = doc.add_heading(title_text, 0)
        title_run = title.runs[0]
        title_run.font.name = '黑体'
        title_run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')

    def _set_default_font(self, doc: Document):
        """设置默认字体为宋体"""
        style = doc.styles['Normal']
        font = style.font
        font.name = '宋体'
        style._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')

    def _add_exam_info_table(self, doc: Document, exam_data: Dict[str, Any]):
        """添加试卷信息表格"""
        info_table = doc.add_table(rows=5, cols=2)
        info_table.style = 'Light Grid Accent 1'

        # 获取当前日期
        today = date.today()
        info_data = [
            ["姓名", []],
            ["年级", exam_data.get('grade', '未知')],
            ["难度", exam_data.get('difficulty', '未知')],
            ["题目数量", str(len(exam_data.get('questions', [])))],
            ["时间", today.strftime("%Y-%m-%d")]
        ]

        for i, (label, value) in enumerate(info_data):
            info_table.cell(i, 0).text = label
            info_table.cell(i, 1).text = value

    def _add_questions(self, doc: Document, questions: list, include_answers: bool):
        """添加题目"""
        for i, question in enumerate(questions, 1):
            # 添加题目标题
            self._add_question_title(doc, i, question)

            # 添加选项（如果有）
            if "options" in question and question["options"]:
                self._add_question_options(doc, question["options"])

            # 根据是否包含答案决定添加内容
            if include_answers:
                self._add_question_with_answers(doc, question)
            else:
                self._add_question_without_answers(doc, question)

            # 根据题型添加不同的间距
            self._add_question_spacing(doc, question.get('type'))

    def _add_question_title(self, doc: Document, index: int, question: Dict[str, Any]):
        """添加题目标题"""
        question_para = doc.add_paragraph()

        # 题号
        question_run = question_para.add_run(f"{index}. ")
        question_run.bold = True
        self._set_font(question_run, '宋体')

        # 题型
        if "type" in question:
            type_run = question_para.add_run(f"({question['type']}) ")
            type_run.italic = True
            self._set_font(type_run, '宋体')

        # 题目内容
        content_run = question_para.add_run(question.get('question', '未知题目'))
        self._set_font(content_run, '宋体')

    def _add_question_options(self, doc: Document, options: list):
        """添加题目选项"""
        for j, opt in enumerate(options):
            option_label = chr(65 + j)  # A, B, C, D...
            option_para = doc.add_paragraph(f"{option_label}. {opt}", style="List Bullet")
            for run in option_para.runs:
                self._set_font(run, '宋体')

    def _add_question_with_answers(self, doc: Document, question: Dict[str, Any]):
        """添加包含答案的题目内容"""
        # 答案
        if "answer" in question:
            answer_para = doc.add_paragraph()
            answer_bold_run = answer_para.add_run("答案：")
            answer_bold_run.bold = True
            self._set_font(answer_bold_run, '宋体')

            answer_content_run = answer_para.add_run(question['answer'])
            self._set_font(answer_content_run, '宋体')

        # 解析
        if "explanation" in question:
            explanation_para = doc.add_paragraph()
            explanation_bold_run = explanation_para.add_run("解析：")
            explanation_bold_run.bold = True
            self._set_font(explanation_bold_run, '宋体')

            explanation_content_run = explanation_para.add_run(question['explanation'])
            self._set_font(explanation_content_run, '宋体')

        # 知识点
        if "knowledge_point" in question:
            knowledge_para = doc.add_paragraph()
            knowledge_bold_run = knowledge_para.add_run("知识点：")
            knowledge_bold_run.bold = True
            self._set_font(knowledge_bold_run, '宋体')

            knowledge_content_run = knowledge_para.add_run(question['knowledge_point'])
            self._set_font(knowledge_content_run, '宋体')

    def _add_question_without_answers(self, doc: Document, question: Dict[str, Any]):
        """添加不包含答案的题目内容"""
        question_type = question.get('type')

        if question_type == '选择题':
            answer_para = doc.add_paragraph("答案：【  】")
            for run in answer_para.runs:
                self._set_font(run, '宋体')
        elif question_type == '解答题':
            # 试题版的简答题不需要横线
            answer_para = doc.add_paragraph("答案：")
            for run in answer_para.runs:
                self._set_font(run, '宋体')
        # 填空题不添加任何答题区域

    def _add_question_spacing(self, doc: Document, question_type: str):
        """根据题型添加不同的间距"""
        if question_type == '解答题':
            # 解答题之间空三行
            doc.add_paragraph()
            doc.add_paragraph()
            doc.add_paragraph()
        elif question_type == '填空题':
            # 填空题之间不换行（不添加空行）
            pass
        else:
            # 其他题型（选择题）正常间距
            doc.add_paragraph()

    def _set_font(self, run, font_name: str):
        """设置字体"""
        run.font.name = font_name
        run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)
    
    def _generate_filepath(self, filename: str = None) -> Path:
        """生成文件路径"""
        if not filename:
            filename = f"exam_{uuid.uuid4().hex[:8]}.docx"
        
        if not filename.endswith('.docx'):
            filename += '.docx'
        
        return self.export_dir / filename
    
    def cleanup_old_files(self, max_files: int = 100):
        """清理旧文件，保持文件数量在合理范围内"""
        try:
            files = list(self.export_dir.glob("*.docx"))
            if len(files) > max_files:
                # 按修改时间排序，删除最旧的文件
                files.sort(key=lambda f: f.stat().st_mtime)
                for file in files[:-max_files]:
                    file.unlink()
                    logger.info(f"清理旧文件: {file}")
        except Exception as e:
            logger.warning(f"清理文件失败: {e}")


# 全局Word导出服务实例
word_export_service = WordExportService()